package com.one.blocks.mvc.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.util.ListUtils;
import com.one.blocks.mvc.enums.BatchResultEnum;
import com.one.blocks.mvc.manager.BatchManager;

import java.util.List;

/**
 * @author linfuxin Created on 2022-07-12 14:12:48
 */
public class BreakOfErrorListener<T, E, Convert extends ExcelConvert<T, E>, Manager extends BatchManager<T> & ExcelManager<T>>
        extends AbstractDataListener<T, E, Convert, Manager> {

    protected static final int BATCH_COUNT = 100;
    protected final List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private Integer errorIndex;
    private int importSuccessCount;
    private int updateSuccessCount;

    public BreakOfErrorListener(Manager manager, Convert convert, UploadParam uploadParam, UploadResult uploadResult, Class<T> tClazz, Class<E> eClazz) {
        super(manager, convert, uploadParam, uploadResult, tClazz, eClazz);
    }

    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        uploadResult.setState(BatchResultEnum.FAILED.getCode());
        uploadResult.setFailedReason(exception.getMessage());
        uploadResult.setDetail(String.format("新增%d条,覆盖%d条,在导入第%d行数据时出现异常!",
                importSuccessCount, updateSuccessCount, context.readRowHolder().getRowIndex()));
        if (exception instanceof ExcelAnalysisStopException) {
            throw exception;
        }
        throw new ExcelAnalysisStopException();
    }

    @Override
    protected void doInvoke(E data, AnalysisContext context) {
        cachedDataList.add(convert.excelToEntity(data));
        // 达到BATCH_COUNT了，往数据库插入一次数据
        // 1.防止数据几万条数据在内存，引起OOM 2.防止一次插入过多的数据 3. 防止频繁插入一条数据
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        super.doAfterAllAnalysed(context);
        saveData();

        uploadResult.setState(BatchResultEnum.SUCCESS.getCode());
        uploadResult.setDetail(String.format("导入成功%d条数据!", importSuccessCount));
    }

    @Override
    protected void updateBatch(List<T> updateDataList) {
        errorIndex = manager.updateBatchByIdOfBreakIfException(updateDataList);
        if (errorIndex != null) {
            updateSuccessCount += errorIndex;
            throw new ExcelAnalysisStopException();
        } else {
            updateSuccessCount += updateDataList.size();
        }
    }

    protected void saveData() {
        errorIndex = manager.insertBatchOfBreakIfException(cachedDataList);
        if (errorIndex != null) {
            importSuccessCount += errorIndex;
            throw new ExcelAnalysisStopException();
        } else {
            importSuccessCount += cachedDataList.size();
        }
    }
}
